package cn.cranzil.registercenter.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.shared.Application;
import com.netflix.eureka.EurekaServerContext;
import com.netflix.eureka.registry.InstanceRegistry;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class UpdateController {

    private final InstanceRegistry instanceRegistry;

    @Autowired
    public UpdateController(EurekaServerContext eurekaServerContext) {
        this.instanceRegistry = eurekaServerContext.getRegistry();
    }

    @PostMapping("/self_update")
    public Object selfUpdate(String appName, MultipartFile[] files) throws IOException {

        // 通过应用名称拿到所有微服务实例
        Application app = this.instanceRegistry.getApplication(appName);

        if (app == null) {
            return "empty";
        }
        List<InstanceInfo> instanceInfos = app.getInstances();

        // 创建返回Map
        Map<String, Object> map = new HashMap<>();
        List<String> okInstances = new ArrayList<>(instanceInfos.size());
        List<String> errorInstances = new ArrayList<>(instanceInfos.size());
        map.put("update_ok_instances", okInstances);
        map.put("update_error_instances", errorInstances);

        // 创建文件集合体
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setCharset(Charset.forName("utf-8"));
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//加上此行代码解决返回中文乱码问题
        for (MultipartFile file : files) {
            builder.addBinaryBody("files", file.getInputStream(), ContentType.MULTIPART_FORM_DATA, file.getOriginalFilename());// 文件流
        }
        HttpEntity entity = builder.build();

        // 挨个更新微服务（需要微服务实现自更新接口）
        for (InstanceInfo instanceInfo : instanceInfos) {
            // 由于Eureka注册中心不能自注册，使用原始的http请求更新所有实例
            String hostname = instanceInfo.getHostName();
            Integer port = instanceInfo.getPort();

            String selfUpdateUrl = String.format("http://%s:%d/self_update", hostname, port);

            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(selfUpdateUrl);
            httpPost.setEntity(entity);

            try{
                CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
                ObjectMapper mapper = new ObjectMapper();
                JsonNode node = mapper.readTree(
                        EntityUtils.toString(httpResponse.getEntity(), Charset.forName("UTF-8"))
                );
                int code = node.findValue("code").asInt();
                if (code == 0) {
                    okInstances.add(instanceInfo.getInstanceId());
                } else {
                    errorInstances.add(instanceInfo.getInstanceId());
                }
            }catch (IOException ignored){
                errorInstances.add(instanceInfo.getInstanceId());
            }
        }
        return map;
    }
}
